var util = require("util");
var events = require("events");
var log4js = require('log4js');
var logger = log4js.getLogger('Player');
var amqCon = require('../util/AMQConnection');
var amqCh = require('../util/AMQChannel');
var uuid = require('uuid');

function Player(name, config) {
    logger.trace("enter constructor");
    events.EventEmitter.call(this);
    this.config = config;
    this.name = name;
    this.id = uuid.v1();
    this.on('data', Player.processData);
    this.on('client_data', Player.processClientData);
}

util.inherits(Player, events.EventEmitter);

module.exports = Player;

Player.Player = Player;

Player.init = function (cb) {
    logger.trace('enter init');
    var that = this;
    this.amqCon = amqCon.getInstance();
    this.key = uuid.v4();
    that.chReceive = new amqCh.AMQChannel(that.amqCon);
    that.chReceive.createExchange(that.config.players.exchange, that.key, function (obj2) {
        if (obj2 === true) {
            logger.debug('exchange ok, bind queue to this exchange');
            that.chReceive.bindQueue('', null, function (msg) {
                that.emit('data', JSON.parse(msg.content.toString()), that);
            }, true, function (obj3) {
                if (obj3 === true) {
                    logger.debug('bind queue ok, create table manager channel');
                    that.chTableManager = new amqCh.AMQChannel(that.amqCon);
                    that.chTableManager.createExchange(that.config.tableManager.exchange, that.config.tableManager.key, function (obj4) {
                        if (obj4 === true) {
                            logger.debug('transmit channel ok');
                            cb(true);
                        } else {
                            logger.error('cannot create transmit channel');
                            logger.error(obj4);
                            cb(obj4);
                        }
                    });
                } else {
                    logger.error('cannot bind queue');
                    logger.error(obj3);
                    cb(obj3);
                }
            });
        } else {
            logger.error('cannot create exchange');
            logger.error(obj2);
            cb(obj2);
        }
    });
};

Player.prototype.initWithSocket = function (socket, cb) {
    // init all variables here
    logger.trace("enter init with socket");
    var that = this;
    this.socket = socket;
    this.type = 'user';
    Player.init.call(this, function (result) {
        if (result === true) {
            logger.debug('init ok');
            that.socket.on('message', function (data) {
                that.emit('client_data', data, that);
            });
        } else {
            logger.debug('init not ok, disconnect to client');
            that.socket.emit('error', {message: 'cannot contact server'});
        }
    });
};

Player.prototype.initWithAI = function (tableKey, cb) {
    // init all variables here
    logger.trace("enter init with ai");
    this.type = 'ai';
    var that = this;
    Player.init.call(this, function (result) {
        if (result === true) {
            that.joinTable(tableKey);
            cb(true);
        } else {
            cb(result);
        }
    });
};

Player.prototype.findTable = function () {
    logger.trace('enter findTable');
    if (this.chTableManager !== null) {
        this.chTableManager.sendMessage({
            action: 'find_table',
            player: this.name,
            type: this.type,
            key: this.key
        });
    } else {
        logger.warn('transmit channel is null');
    }
};

Player.prototype.joinTable = function (tableKey) {
    logger.trace('enter joinTable');
    var that = this;
    that.chTable = new amqCh.AMQChannel(that.amqCon);
    that.chTable.createExchange(that.config.tables.exchange, tableKey, function (obj4) {
        if (obj4 === true) {
            logger.debug('table channel ok');
            that.chTable.sendMessage({
                action: 'join_table',
                player: that.name,
                type: that.type,
                key: that.key
            });
        } else {
            logger.error('cannot create channel to table: ' + tableKey);
            logger.error(obj4);
        }
    });
};

Player.processData = function (data, that) {
    logger.trace('enter processData');
    switch (data.action) {
        case 'find_table':
            if (data.error === undefined) {
                logger.debug('find a table: ' + data.table + ', join it now');
                if (that.type === 'user') {
                    var rData = {};
                    rData.success = true;
                    rData.body = {
                        action: 'find_table',
                        table: data.table
                    };
                    that.socket.emit('message', rData);
                }
                logger.info('player ' + that.name + ' join the table ' + data.table);
                that.joinTable(data.tableKey);
                that.tableKey = data.tableKey;
            } else {
                logger.warn('cannot find a table');
                logger.warn(data.error);
                if (that.type === 'user') {
                    var rData = {};
                    rData.success = false;
                    rData.body = {
                        action: 'find_table',
                        error: 'no table, please wait a moment and reconnect later'
                    };
                    that.socket.emit('message', rData);
                }
            }
            break;

        case 'join_table':
            if (data.error === undefined) {
                logger.debug('join table: ' + data.table + ' successfully');
                // bind a queue for table group
                that.chTableGroup = new amqCh.AMQChannel(that.amqCon);
                that.tableGroupKey = data.tableGroupKey;
                that.chTableGroup.createExchange(that.config.tables.exchange, data.tableGroupKey, function (obj2) {
                    if (obj2 === true) {
                        logger.debug('exchange ok, bind queue to this exchange');
                        that.chTableGroup.bindQueue('', null, function (msg) {
                            that.emit('data', JSON.parse(msg.content.toString()), that);
                        }, true, function (obj3) {
                            if (obj3 === true) {
                                logger.debug('bind queue ok, create table manager channel');
                            } else {
                                logger.error('cannot bind queue');
                                logger.error(obj3);
                                // fatal error, need reconnect
                            }
                        });
                    } else {
                        logger.error('cannot create exchange');
                        logger.error(obj2);
                    }
                });

                if (that.type === 'user') {
                    var rData = {};
                    rData.success = true;
                    rData.body = {
                        action: 'join_table',
                        table: data.table
                    };
                    that.socket.emit('message', rData);
                }
            } else {
                logger.warn('cannot join the table: ' + data.table + ' because of: ');
                logger.warn(data.error);
                if (that.type === 'user') {
                    var rData = {};
                    rData.success = false;
                    rData.body = {
                        action: 'join_table',
                        error: 'cannot join the table',
                        table: data.table
                    };
                    that.socket.emit('message', rData);
                }
            }
            break;
        case 'destroy':
            that.destroy();
            break;
        default:
            logger.debug('cannot process action: ' + data.action);
            break;
    }
};

Player.processClientData = function (data, that) {
    logger.trace('enter processClientData');
    logger.debug('data from client');
    logger.debug(data);

    switch (data.action) {
        case 'find_table':
            that.findTable();
            break;

        case 'disconnect':
            if (that.chTable !== undefined) {
                that.chTable.sendMessage({
                    action: 'disconnect',
                    player: that.name,
                    playerID: that.id
                });
                that.destroy();
            }
            break;

        default:
            break;
    }
};

Player.prototype.sendDestroyMessage = function () {
    logger.trace('enter sendDestroyMessage');
    var that = this;
    var ch = new amqCh.AMQChannel(that.amqCon);
    ch.createExchange(that.config.playerManager.exchange, that.config.playerManager.key, function (obj4) {
        if (obj4 === true) {
            logger.debug('transmit channel ok');
            ch.sendMessage({
                action: 'delete_player',
                playerID: that.id
            });
        } else {
            logger.error('cannot create transmit channel');
            logger.error(obj4);
        }
    });
};

Player.prototype.destroy = function () {
    logger.trace('enter destroy');
    logger.info('destroy player: ' + this.name);

    if (this.chReceive !== undefined) {
        this.chReceive.disconnect();
    }
    if (this.chTable !== undefined) {
        this.chTable.disconnect();
    }
    if (this.chTableGroup !== undefined) {
        this.chTableGroup.disconnect();
    }
    if (this.chTableManager !== undefined) {
        this.chTableManager.disconnect();
    }
};
